﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Net;
using System.IO;
using Lidgren;
using Lidgren.Network;

namespace OnlineQuiz
{
    public enum Headers : byte
    {
        NewPlayer,
        PlayerData,
        Text,
        PlayerDisconnected
    }

    public enum DataType : byte
    {
        String,
        Int,
        Bool,
        Float
    }

    public class Program
    {
        static NetPeerConfiguration Config;
        static NetClient Client;
        static List<Player> Players;
        static Player Me;

        static void Main(string[] args)
        {
            try
            {
                Config = new NetPeerConfiguration("Quiz");
                Players = new List<Player>();
                Client = new NetClient(Config);
                new Thread(new ThreadStart(ReceiveData)).Start();
                Client.Start();
                Client.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7777));
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR: " + ex.ToString());
            }
        }

        static void ReceiveData()
        {
            while (true)
            {
                NetIncomingMessage incmsg;
                NetOutgoingMessage outmsg;

                if ((incmsg = Client.ReadMessage()) != null)
                {
                    switch (incmsg.MessageType)
                    {
                        case NetIncomingMessageType.StatusChanged:

                            if (Client.ConnectionStatus == NetConnectionStatus.Connected)
                            {
                                Console.WriteLine("You're connected!");
                                outmsg = Client.CreateMessage();
                                outmsg.Write((byte)Headers.NewPlayer);
                                Client.SendMessage(outmsg, NetDeliveryMethod.ReliableSequenced);
                            }

                            break;

                        case NetIncomingMessageType.Data:

                            Player newPlayer;
                            int playerid;
                            Headers header = (Headers)incmsg.ReadByte();

                            switch (header)
                            {
                                case Headers.NewPlayer:

                                    int playersCount = incmsg.ReadInt32();

                                    if (playersCount <= 1)
                                    {
                                        newPlayer = new Player();
                                        incmsg.ReadAllProperties(newPlayer);
                                        Players.Add(newPlayer);
                                        Me = newPlayer;
                                    }
                                    else
                                    {
                                        for (int i = 0; i < playersCount; i++)
                                        {
                                            newPlayer = new Player();
                                            incmsg.ReadAllProperties(newPlayer);
                                            Players.Add(newPlayer);
                                        }

                                        Me = Players[playersCount-1];
                                    }

                                    new Thread(new ThreadStart(InputManager)).Start();
                                    break;

                                case Headers.PlayerData:
                                   
                                    playerid = incmsg.ReadInt32();
                                    
                                    if ((Players.Count <= playerid))
                                    {
                                        newPlayer = new Player();
                                        incmsg.ReadAllProperties(newPlayer);
                                        Players.Add(newPlayer);
                                    }
                                    else
                                    {
                                        incmsg.ReadAllProperties(Players[playerid]);
                                    }

                                    break;

                                case Headers.PlayerDisconnected:

                                    playerid = incmsg.ReadInt32();
                                    Players.RemoveAt(playerid);
                                    break;
                            }

                            break;
                    }
                }
            }
        }

        static void InputManager()
        {
            while (true)
            {
                string input;

                if ((input = Console.ReadLine()) != null)
                {
                    string[] args = input.Split(' ');
                    int len = args.Length-1;

                    switch (args[0].ToLower())
                    {
                        case "/say":

                            if (len == 2)
                            {
                                try
                                {
                                    int choice = int.Parse(args[1]);
                                    string message = args[2];
                                    NetOutgoingMessage outmsg = Client.CreateMessage();
                                    outmsg.Write((byte)Headers.Text);
                                    outmsg.Write(message);

                                    if (choice == 0)
                                    {
                                        Client.SendMessage(outmsg, NetDeliveryMethod.ReliableSequenced);
                                    }
                                    else
                                    {
                                        throw new NotImplementedException();
                                    }
                                }
                                catch
                                {
                                    Console.WriteLine("An error occured.");
                                }
                            }
                            else Console.WriteLine("USAGE: /say [Server - 0, All Client - 1] [Message]");
                            break;

                        case "/me":

                            Console.WriteLine(Me.ToString());
                            break;

                        case "/all":

                            foreach (Player player in Players)
                            {
                                Console.WriteLine(player.ToString());
                            }

                            break;

                        case "/exit":

                            Client.Disconnect("Fake");
                            break;
                    }
                }
            }
        }
    }

    public class Player
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Question { get; set; }
        public string Answer { get; set; }
        public bool Turn;

        public Player()
        {
            Turn = false;
        }

        public override string ToString()
        {
            return string.Format("Name: {0}, Question: {1}, Answer {2}, Turn {3}", Name, Question, Answer, Turn);
        }

        public void DataUpdate(NetClient client)
        {
            NetOutgoingMessage outmsg = client.CreateMessage();
            outmsg.Write((byte)Headers.PlayerData);
            outmsg.WriteAllProperties(this);
            client.SendMessage(outmsg, NetDeliveryMethod.ReliableSequenced);
        }
    }
}
